package me.pppploi8.webmcs.main.urlmapping;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileItemFactory;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.io.FileUtils;

import me.pppploi8.webmcs.http.jetty.HttpUrlMapping;
import me.pppploi8.webmcs.main.tools.CompressUtils;
import me.pppploi8.webmcs.main.tools.Utils;
import me.pppploi8.webmcs.minecraft.server.core.McServerCore;
import me.pppploi8.webmcs.minecraft.server.core.McServerFactory;

public class WebmcsFileService extends HttpUrlMapping{
	private McServerCore msc;
	private static SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd");
	private static String[] emptyArr = new String[0];
	
	public WebmcsFileService(){
		this.msc = McServerFactory.getMcServerCore();
	}
	/**
	 * 获取文件的文本内容
	 * 参数 path 文件路径
	 * 参数 encoding 编码(不填写默认UTF-8)
	 * 返回值 PARAMERROR 参数错误 NOTFOUND 未找到文件 EXCEPTION 内部异常(抛出错误给exception) ，成功额外返回content
	 */
	public Object getFileContent(){
		Map<String, Object> ret = Utils.getResultMap();
		String path = getRequest().getParameter("path");
		if (Utils.checkParamIsBlank(ret, path)){
			return ret;
		}
		String encoding = getRequest().getParameter("encoding");
		if (Utils.stringIsBlank(encoding)){
			encoding = "UTF-8";
		}
		File file = new File(msc.getServerPath() + Utils.filterPath(path));
		if (file.exists()){
			try{
				ret.put("content", FileUtils.readFileToString(file, encoding));
				ret.put("status", true);
			}catch(Exception e){
				ret.put("msg", "EXCEPTION");
				ret.put("exception", e.getMessage());
				e.printStackTrace();
			}
		}else{
			ret.put("msg", "NOTFOUND");
		}
		return ret;
	}
	/**
	 * 设置文件的文本内容
	 * 参数 path 文件路径
	 * 参数 encoding 文件编码
	 * 参数 content 文件内容
	 * 返回值 PARAMERROR 参数错误 EXCEPTION 内部异常(抛出错误给exception)
	 */
	public Object putFileContent(){
		Map<String, Object> ret = Utils.getResultMap();
		String path = getRequest().getParameter("path");
		String encoding = getRequest().getParameter("encoding");
		String content = getRequest().getParameter("content");
		if (Utils.checkParamIsBlank(ret, path, encoding)){
			return ret;
		}
		try{
			File file = new File(msc.getServerPath() + Utils.filterPath(path));
			FileUtils.write(file, content, encoding);
			ret.put("status", true);
		}catch(Exception e){
			ret.put("msg", "EXCEPTION");
			ret.put("exception", e.getMessage());
			e.printStackTrace();
		}
		return ret;
	}
	/**
	 * 复制文件到指定位置
	 * 页面参数
	 * fileName[] 文件名数组
	 * destDir 目标目录
	 * 返回值
	 * PARAMERROR -> 参数错误
	 * COPYSAME -> 拷贝源目录和目标目录相同
	 * EXCEPTION -> 内部异常
	 */
	public Object copyFiles(){
		Map<String, Object> ret = Utils.getResultMap();
		String[] fileNames = getRequest().getParameterValues("fileName");
		String destDir = getRequest().getParameter("destDir");
		if (Utils.arrayIsBlank(fileNames) || Utils.stringIsBlank(destDir)){
			ret.put("msg", "PARAMERROR");
			return ret;
		}
		try{
			for(String fileName : fileNames){
				File file = new File(msc.getServerPath() + "/" + Utils.filterPath(fileName));
				File destFile = new File(msc.getServerPath() + "/" + Utils.filterPath(destDir) + "/" + file.getName());
				if (file.equals(destFile)){
					ret.put("msg", "COPYSAME");
					return ret;
				}
				if (file.exists()){
					if (file.isFile()){
						FileUtils.copyFile(file, destFile);
					}else{
						FileUtils.copyDirectory(file, destFile);
					}
				}
			}
			ret.put("status", true);
		}catch(Exception e){
			e.printStackTrace();
			ret.put("msg", "EXCEPTION");
			ret.put("exception", e.getMessage());
		}
		return ret;
	}
	public Object uploadFiles(){
		Map<String, Object> ret = Utils.getResultMap();
    	if(ServletFileUpload.isMultipartContent(getRequest())){
    		try{
    			FileItemFactory factory = new DiskFileItemFactory();
    			ServletFileUpload fileUpload = new ServletFileUpload(factory);
    			fileUpload.setHeaderEncoding("UTF-8");
    			List<FileItem> list = fileUpload.parseRequest(getRequest());
    			if (list.size() == 0){
    				throw new Exception("未正确上传文件！");
    			}
    			String path = null;
    			for(FileItem file : list){
    				if (file.getFieldName().equals("path")){
    					path = file.getString("UTF-8");
    					break;
    				}
    			}
    			if (path == null){
    				ret.put("msg", "PARAMERROR");
    				return ret;
    			}
    			for(FileItem file : list){
    				if ("file".equals(file.getFieldName())){
    					msc.getServerPath().mkdirs();
    		            File destFile = new File(msc.getServerPath() + Utils.filterPath(path) + "/" + Utils.getFilenameByPath(file.getName()));
    		            if (destFile.exists()){
    		            	destFile.delete();
    		            }
    		            FileUtils.copyInputStreamToFile(file.getInputStream(), destFile);
    				}
    			}
    			ret.put("status", true);
    		}catch(Exception e){
    			e.printStackTrace();
    			ret.put("exception", e.getMessage());
        		ret.put("msg", "EXCEPTION");
    		}
    	}else{
    		ret.put("msg", "CHECKERROR");
    	}
    	return ret;
	}
	public Object renameFile(){
		Map<String, Object> ret = Utils.getResultMap();
		String path = getRequest().getParameter("path");
		String filename = getRequest().getParameter("filename");
		if (Utils.checkParamIsBlank(ret, path, filename)){
			return ret;
		}
		try{
			File file = new File(msc.getServerPath() + Utils.filterPath(path));
			File destFile = new File(file.getParent() + "/" + filename);
			FileUtils.moveFile(file, destFile);
			ret.put("status", true);
		}catch(Exception e){
			e.printStackTrace();
			ret.put("status", "EXCEPTION");
			ret.put("exception", e.getMessage());
		}
		return ret;
	}
	/**
	 * 移动文件到指定位置
	 * 页面参数
	 * fileName[] 文件名数组
	 * destDir 目标目录
	 * 返回值
	 * PARAMERROR -> 参数错误
	 * MOVESAME -> 移动源目录和目标目录相同
	 * EXCEPTION -> 内部异常
	 */
	public Object moveFiles(){
		Map<String, Object> ret = Utils.getResultMap();
		String[] fileNames = getRequest().getParameterValues("fileName");
		String destDir = getRequest().getParameter("destDir");
		if (Utils.arrayIsBlank(fileNames) || Utils.stringIsBlank(destDir)){
			ret.put("msg", "PARAMERROR");
			return ret;
		}
		try{
			for(String fileName : fileNames){
				File file = new File(msc.getServerPath() + "/" + Utils.filterPath(fileName));
				File destFile = new File(msc.getServerPath() + "/" + Utils.filterPath(destDir) + "/" + file.getName());
				if (file.equals(destFile)){
					ret.put("msg", "MOVESAME");
					return ret;
				}
				moveFile(file, destFile);
			}
			ret.put("status", true);
		}catch(Exception e){
			e.printStackTrace();
			ret.put("msg", "EXCEPTION");
		}
		return ret;
	}
	private void moveFile(File srcFile, File destFile) throws IOException{
		if (srcFile.isFile()){
			if (destFile.exists()){
				destFile.delete();
			}
			FileUtils.moveFile(srcFile, destFile);
		}else{
			for(File f : srcFile.listFiles()){
				moveFile(f, new File(destFile.getPath() + "/" + f.getName()));
			}
			FileUtils.deleteDirectory(srcFile);
		}
	}
	public Object download() throws IOException{
		String path = getRequest().getParameter("path");
		if (path == null || path.equals("")){
			getResponse().sendError(404);
			return null;
		}
		path = Utils.filterPath(path);
		File file = new File(msc.getServerPath().getAbsolutePath() + path);
		if (!file.exists() || !file.isFile()){
			getResponse().sendError(404);
			return null;
		}
		getResponse().addHeader("Content-Length", file.length()+"");
		getResponse().addHeader("Content-Type", "application/octet-stream");
		getResponse().addHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(file.getName(),"UTF-8"));
		OutputStream os = getResponse().getOutputStream();
		InputStream is = new FileInputStream(file);
		byte[] bytes = new byte[4096];
		int i = 0;
		while((i = is.read(bytes))!=-1)
			os.write(bytes,0,i);
		is.close();
		os.flush();
		os.close();
		return null;
	}
	public String mkdir(){
		String path = getRequest().getParameter("path");
		if (path == null || path.equals(""))
			return "{\"status\":false,\"msg\":\"PARAMERROR\"}";
		path = Utils.filterPath(path);
		File file = new File(msc.getServerPath().getAbsolutePath() + path);
		if (file.exists()){
			return "{\"status\":false,\"msg\":\"DIREXITS\"}";
		}
		if (file.mkdirs()){
			return "{\"status\":true}";
		}
		return "{\"status\":false,\"msg\":\"NAMEERROR\"}";
	}
	/**
	 * 解压文件结构
	 * 参数 filePath 压缩文件路径
	 * 参数 destDir 解压到目标目录
	 * 返回 PARAMERROR 参数错误 EXCEPTION 内部异常(额外字段exception展示原因)
	 */
	public Object unCompress(){
		String filePath = getRequest().getParameter("filePath");
		String destDir = getRequest().getParameter("destDir");
		Map<String, Object> ret = Utils.getResultMap();
		if (Utils.stringIsBlank(filePath) || Utils.stringIsBlank(destDir)){
			ret.put("msg", "PARAMERROR");
			return ret;
		}
		try{
			CompressUtils.unCompress(
					new File(msc.getServerPath() + Utils.filterPath(filePath)),
					new File(msc.getServerPath() + Utils.filterPath(destDir)));
			ret.put("status", true);
		}catch(Exception e){
			e.printStackTrace();
			ret.put("exception", e.getMessage());
			ret.put("msg", "EXCEPTION");
		}
		return ret;
	}
	/**
	 * 压缩文件接口
	 * 参数 saveFile 保存压缩文件路径
	 * 参数 fileName 压缩文件数组
	 * 返回 PARAMERROR 参数错误 EXCEPTION 内部压缩异常
	 */
	public Object compressFiles(){
		Map<String, Object> ret = Utils.getResultMap();
		String[] fileNames = getRequest().getParameterValues("fileName");
		String saveFile = getRequest().getParameter("saveFile");
		if(Utils.stringIsBlank(saveFile) || Utils.arrayIsBlank(fileNames)){
			ret.put("msg", "PARAMERROR");
			return ret;
		}
		try{
			File[] files = new File[fileNames.length];
			for(int i=0;i<fileNames.length;i++){
				files[i] = new File(msc.getServerPath() + "/" + Utils.filterPath(fileNames[i]));
			}
			File outputFile = new File(msc.getServerPath() + "/" + Utils.filterPath(saveFile));
			outputFile.getParentFile().mkdirs();
			CompressUtils.compressToSevenZ(files, outputFile);
			ret.put("status", true);
		}catch(Exception e){
			e.printStackTrace();
			ret.put("msg", "EXCEPTION");
		}
		return ret;
	}
	public Object delfiles(){
		Map<String, Object> ret = Utils.getResultMap();
		String[] fileNames = getRequest().getParameterValues("fileName");
		if (fileNames.length == 0){
			ret.put("msg", "PARAMERROR");
			return ret;
		}
		try{
			for(String s : fileNames){
				File file = new File(msc.getServerPath() + Utils.filterPath(s));
				if (file.exists()){
					if (file.isDirectory()){
						FileUtils.deleteDirectory(file);
					}else{
						file.delete();
					}
				}
			}
			ret.put("status", true);
		}catch(Exception e){
			e.printStackTrace();
			ret.put("msg", "UNKNOWNERROR");
			ret.put("exception", e.getMessage());
		}
		return ret;
	}
	public Object getfiles(){
		Map<String,Object> ret = Utils.getResultMap();
		String path = getRequest().getParameter("path");
		if (path == null || path.equals("")){
			ret.put("msg", "PATHERROR");
			return ret;
		}
		path = Utils.filterPath(path);
		File file = new File(msc.getServerPath().getAbsolutePath() + path);
		if (!file.exists() || file.isFile()){
			ret.put("files",emptyArr);
			ret.put("dirs", emptyArr);
			ret.put("status", true);
			return ret;
		}
		List<String[]> filelist = new ArrayList<>();
		List<String[]> dirlist = new ArrayList<>();
		File serverPath = msc.getServerPath();
		dirlist.add(new String[]{"..",getPath(serverPath,file.getParentFile())});
		File[] files = file.listFiles();
		for(File f : files){
			if (f.isDirectory()){
				dirlist.add(new String[]{f.getName(),getPath(serverPath,f)});
			}else{
				filelist.add(new String[]{f.getName(),f.length()+"",getTimeString(f.lastModified()),getPath(serverPath,f)});
			}
		}
		ret.put("files",filelist);
		ret.put("dirs", dirlist);
		ret.put("status", true);
		return ret;
	}
	private String getPath(File root,File file){
		String rootPath = root.getAbsolutePath();
		String filePath = file.getAbsolutePath();
		if(filePath.length()>=rootPath.length()){
			rootPath = filePath.substring(rootPath.length(), filePath.length()).replace("\\", "/");
			if (rootPath.equals(""))
				return "/";
			return rootPath;
		}else{
			return "/";
		}
	}
	private String getTimeString(long time){
        return sdf.format(time);
    }
}
